{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#请先运行此代码\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\" \n",
    "#这玩意可以让代码块分行输出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 错误处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### try"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "try...\n",
      "except: division by zero\n",
      "finally...\n",
      "END\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    print('try...')\n",
    "    r = 10 / 0\n",
    "    print('result:', r)\n",
    "except ZeroDivisionError as e:#如果发生除0错误\n",
    "    print('except:', e)\n",
    "finally:#只要有就一定会被执行\n",
    "    print('finally...')\n",
    "print('END')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "try...\n",
      "ValueError: invalid literal for int() with base 10: 'a'\n",
      "finally...\n",
      "END\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    print('try...')\n",
    "    r = 10 / int('a')\n",
    "    print('result:', r)\n",
    "except ValueError as e:#如果是这种错误怎样怎样\n",
    "    print('ValueError:', e)\n",
    "except ZeroDivisionError as e:#如果是这种错误怎样怎样\n",
    "    print('ZeroDivisionError:', e)\n",
    "else:\n",
    "    print('no error!')#如果没错误就执行这个\n",
    "finally:\n",
    "    print('finally...')\n",
    "print('END')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Python的错误其实也是class，所有的错误类型都继承自BaseException"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    foo()\n",
    "except ValueError as e:\n",
    "    print('ValueError')\n",
    "except UnicodeError as e:#永远也捕获不到UnicodeError，因为UnicodeError是ValueError的子类\n",
    "    print('UnicodeError')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 使用try...except捕获错误还有一个巨大的好处，就是可以跨越多层调用，比如函数main()调用bar()，bar()调用foo()，结果foo()出错了，这时，只要main()捕获到了，就可以处理："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def foo(s):\n",
    "    return 10 / int(s)\n",
    "\n",
    "def bar(s):\n",
    "    return foo(s) * 2\n",
    "\n",
    "def main():\n",
    "    try:\n",
    "        bar('0')\n",
    "    except Exception as e:\n",
    "        print('Error:', e)\n",
    "    finally:\n",
    "        print('finally...')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 记录错误"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Python内置的logging模块可以非常容易地记录错误信息："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "ERROR:root:division by zero\n",
      "Traceback (most recent call last):\n",
      "  File \"C:\\Users\\89859\\AppData\\Local\\Temp/ipykernel_14312/1371240815.py\", line 11, in main\n",
      "    bar('0')\n",
      "  File \"C:\\Users\\89859\\AppData\\Local\\Temp/ipykernel_14312/1371240815.py\", line 7, in bar\n",
      "    return foo(s) * 2\n",
      "  File \"C:\\Users\\89859\\AppData\\Local\\Temp/ipykernel_14312/1371240815.py\", line 4, in foo\n",
      "    return 10 / int(s)\n",
      "ZeroDivisionError: division by zero\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "END\n"
     ]
    }
   ],
   "source": [
    "import logging\n",
    "\n",
    "def foo(s):\n",
    "    return 10 / int(s)\n",
    "\n",
    "def bar(s):\n",
    "    return foo(s) * 2\n",
    "\n",
    "def main():\n",
    "    try:\n",
    "        bar('0')\n",
    "    except Exception as e:\n",
    "        logging.exception(e)\n",
    "\n",
    "main()\n",
    "print('END')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 这样还不会中断程序运行，还能正常退出，把错误记录到日志文件里"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 抛出错误"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 因为错误是class，捕获一个错误就是捕获到该class的一个实例。因此，错误并不是凭空产生的，而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误，我们自己编写的函数也可以抛出错误。\n",
    "\n",
    "* 如果要抛出错误，首先根据需要，可以定义一个错误的class，选择好继承关系，然后，用raise语句抛出一个错误的实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "FooError",
     "evalue": "invalid value: 0",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mFooError\u001b[0m                                  Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_14312/3804437880.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      8\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[1;36m10\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mn\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mfoo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'0'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_14312/3804437880.py\u001b[0m in \u001b[0;36mfoo\u001b[1;34m(s)\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      6\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[0mn\u001b[0m\u001b[1;33m==\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m         \u001b[1;32mraise\u001b[0m \u001b[0mFooError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'invalid value: %s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0ms\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m#手动抛出异常\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      8\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[1;36m10\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mn\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mFooError\u001b[0m: invalid value: 0"
     ]
    }
   ],
   "source": [
    "class FooError(ValueError):#继承自ValueError类\n",
    "    pass\n",
    "\n",
    "def foo(s):\n",
    "    n = int(s)\n",
    "    if n==0:\n",
    "        raise FooError('invalid value: %s' % s)#手动抛出异常\n",
    "    return 10 / n\n",
    "\n",
    "foo('0')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* raise语句如果不带参数，就会把当前错误原样抛出。此外，在except中raise一个Error，还可以把一种类型的错误转化成另一种类型："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "input error!",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mZeroDivisionError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_14312/2643959433.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m     \u001b[1;36m10\u001b[0m \u001b[1;33m/\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mZeroDivisionError\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_14312/2643959433.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      2\u001b[0m     \u001b[1;36m10\u001b[0m \u001b[1;33m/\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mZeroDivisionError\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m     \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'input error!'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m: input error!"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    10 / 0\n",
    "except ZeroDivisionError:\n",
    "    raise ValueError('input error!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 调试"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### print\n",
    "* 直接把print放在程序中，到时候不好删，不用他"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 断言"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 凡是用print()来辅助查看的地方，都可以用断言（assert）来替代："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (Temp/ipykernel_14312/2554172895.py, line 1)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"C:\\Users\\89859\\AppData\\Local\\Temp/ipykernel_14312/2554172895.py\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m    $ python -O err.py\u001b[0m\n\u001b[1;37m    ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "def foo(s):\n",
    "    n = int(s)\n",
    "    assert n != 0, 'n is zero!'  #表达式n != 0应该是True，否则后面的程序肯定会出错！\n",
    "    return 10 / n\n",
    "\n",
    "def main():\n",
    "    foo('0')\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 程序中如果到处充斥着assert，和print()相比也好不到哪去。不过，启动Python解释器时可以用-O参数来关闭assert："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "$ python -O err.py #关闭后，你可以把所有的assert语句当成pass来看"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### logging"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* logging的另一个好处是通过简单的配置，一条语句可以同时输出到不同的地方，比如console和文件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "logging.basicConfig(level=logging.INFO)\n",
    "#就是logging的好处，它允许你指定记录信息的级别，有debug，info，warning，error等几个级别\n",
    "\n",
    "s = '0'\n",
    "n = int(s)\n",
    "logging.info('n = %d' % n)\n",
    "print(10 / n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **pdb和pdb.set_trace()先跳过**，因为ide的单步执行和断点挺好用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 跳过调试中的pdb和pdb.set_trace()、单元测试和文档测试"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "2e918aaa81d99c652401bdd1a0c185581595fb477ac919641bd65261b5d7782a"
  },
  "kernelspec": {
   "display_name": "Python 3.9.7 64-bit ('base': conda)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
